package dom.example.lucene.utils;

import bom.example.common.utils.PathUtils;
import com.alibaba.fastjson.JSON;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author X.I.O
 * @title: Lucene
 * @projectName demo
 * @description: TODO
 * @date 2021/11/6 21:13
 */
public class Lucene {

    /**
     * 构建索引
     * @param indexName
     * @return
     * @throws Exception
     */
    public static IndexSearcher createIndexSearcher(String indexName) throws Exception{
        Directory directory=getDirectory(indexName);
        DirectoryReader ireader = DirectoryReader.open(directory);
        return new IndexSearcher(ireader);
    }

    /**
     * 获取索引目录
     * @param indexName
     * @return
     * @throws Exception
     */
    private static Directory getDirectory(String indexName) throws Exception{
        File file=getFilePath(indexName);
        System.out.println(file.getPath());
        Directory directory = FSDirectory.open(file);
        return directory;
    }

    /**
     * 为索引提供存储
     * @param indexPath
     * @return
     */
    private static File getFilePath(String indexPath){
        File file= PathUtils.getPathByName(LuceneContants.INDEX_DICTORY,indexPath);
        return file;
    }

    /**
     * 构建索引的数据写入
     * @param indexName
     * @return
     * @throws Exception
     */
    public static IndexWriter getIndexWriter(String indexName) throws Exception{
        Directory directory=getDirectory(indexName);
        System.out.println(directory);
        IndexWriterConfig indexWriterConfig=analyzerCreate();
        IndexWriter indexWriter=new IndexWriter(directory,indexWriterConfig);
        return indexWriter;
    }

    /**
     * 分词配置构建
     * @return
     */
    private static IndexWriterConfig analyzerCreate(){
        Analyzer analyzer = new StandardAnalyzer();
        IndexWriterConfig indexConfig = new IndexWriterConfig(Version.LUCENE_4_10_2, analyzer);
        return indexConfig;
    }

    /**
     * 将搜索到的数据转成document文档
     * @param scoreDocs
     * @param indexSearcher
     * @return
     * @throws Exception
     */
    public static List<Document> getDocumentByScore(ScoreDoc[] scoreDocs, IndexSearcher indexSearcher) throws Exception{
        List<Document> documents=new ArrayList<>(scoreDocs.length);
        for (ScoreDoc scoreDoc : scoreDocs) {
            // 根据文档Id, 查询文档数据 -- 相当于关系数据库中根据主键Id查询数据
            Document doc = indexSearcher.doc(scoreDoc.doc);
            documents.add(doc);
        }
        return documents;
    }

    /**
     * 将搜索得到的document 集合文档转成  Map<String,Object>集合
     * @param documentList
     * @return
     */
    public static List<Map<String, Object>> getDocumentArrayToMapArray(List<Document> documentList){
        List<Map<String, Object>> mapList=new ArrayList<>(documentList.size());
        documentList.stream().forEach(e->{
            Map<String, Object> objectMap=getDocumentToMap(e);
            mapList.add(objectMap);
        });
        return mapList;
    }

    /**
     * 将搜索得到的document 文档转成  Map<String,Object>
     * @param document
     * @return
     */
    public static Map<String, Object> getDocumentToMap(Document document){
        Map<String, Object> map=new HashMap<>();
        document.forEach((k)->{
            map.put(k.name(),k.stringValue());
        });
        return map;
    }

    public static TopDocs getQueryDoc(IndexSearcher indexSearcher, String keyword, String field, Integer total) throws Exception{
        Query query=createQuery(keyword,field);
        TopDocs topDocs = indexSearcher.search(query, total);
        return topDocs;
    }



    /**
     * 构建查询条件
     * @param keyword
     * @param field
     * @return
     * @throws Exception
     */
    private static Query createQuery(String keyword, String field) throws Exception{
        Analyzer analyzer = new StandardAnalyzer();
        QueryParser parser = new QueryParser(field, analyzer);
        return parser.parse(field+":"+keyword);
    }

    /**
     * 批量将map<String,Object>转成List<Document>
     * @param mapList
     * @return
     */
    public static List<Document> listToDocument(List<Map<String, Object>> mapList){
        List<Document> documents=new ArrayList<>(mapList.size());
        for (int i = 0; i < mapList.size(); i++) {
            Map<String, Object> objectMap=mapList.get(i);
            Document document=createDocument(objectMap);
            documents.add(document);
        }
        return documents;
    }

    /**
     * 将map转为Document
     * @param stringObjectMap
     * @return
     */
    public static Document createDocument(Map<String, Object> stringObjectMap) {
        Document doc = new Document();
        for (Map.Entry<String, Object> objectEntry:stringObjectMap.entrySet()){
            System.out.println(JSON.toJSONString(objectEntry));
            doc.add(new TextField(objectEntry.getKey(), JSON.toJSONString(objectEntry.getValue()) , Field.Store.YES));
        }
        System.out.println(JSON.toJSONString(doc));
        return doc;
    }

    public static <T> List<Map<String, Object>> objectsToMaps(List<T> tList){
        List<Map<String, Object>> objects=new ArrayList<>();
        for (int i = 0; i < tList.size() ; i++) {
            T t=tList.get(i);
            Map<String, Object> objectMap=objectToMap(t);
            objects.add(objectMap);
        }
        return objects;
    }

    public static <T> Map<String, Object> objectToMap(T t){
        Map<String, Object> objectMap=new HashMap<>();
        if(t==null){
            return objectMap;
        }
        Class<T> cls=(Class<T>)t.getClass();
        java.lang.reflect.Field[] fields=cls.getDeclaredFields();
        try {
            for (int i = 0; i < fields.length ; i++) {
                java.lang.reflect.Field field=fields[i];
                field.setAccessible(true);
                String fieldName=field.getName();
                Object value=field.get(t);
                objectMap.put(fieldName,value);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return objectMap;
    }

    public static <T> T mapToObject(Map<String, Object> objectMap,Class<T> tClass){
        T t=null;
        try {
            t=tClass.newInstance();
            java.lang.reflect.Field[] fields=tClass.getDeclaredFields();
            for (int i = 0; i < fields.length; i++) {
                java.lang.reflect.Field field=fields[i];
                field.setAccessible(true);
                String fieldName=field.getName();
                Object value=objectMap.get(fieldName);
                field.set(t,value);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return t;
    }

    public static <T> List<T> mapsToObjects(List<Map<String, Object>> objects,Class<T> cls){
        List<T> tList=new ArrayList<>();
        for (int i = 0; i < objects.size() ; i++) {
            Map<String, Object> objectMap=objects.get(i);
            T t=mapToObject(objectMap,cls);
            tList.add(t);
        }
        return tList;
    }

}
